/*
 * PWM测试程序主入口
 * 功能：通过Linux sysfs接口控制PWM设备进行测试
 * 作者：test_code项目
 * 平台：Linux嵌入式系统
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <getopt.h>
#include <signal.h>
#include "pwm_utils.h"

static volatile int running = 1;

void signal_handler(int sig) {
    if (sig == SIGINT || sig == SIGTERM) {
        printf("\n接收到退出信号，正在停止PWM...\n");
        running = 0;
    }
}

void print_usage(const char *program_name) {
    printf("用法: %s [选项]\n", program_name);
    printf("PWM测试程序 - Linux sysfs PWM接口测试工具\n\n");
    printf("选项:\n");
    printf("  -c, --chip=CHIP       PWM芯片编号 (默认: 0)\n");
    printf("  -n, --channel=NUM     PWM通道编号 (默认: 0)\n");
    printf("  -p, --period=NS       PWM周期(纳秒) (默认: 1000000)\n");
    printf("  -d, --duty=NS         PWM占空比时间(纳秒) (默认: 500000)\n");
    printf("  -f, --freq=HZ         PWM频率(Hz) (与period互斥)\n");
    printf("  -r, --ratio=PERCENT   占空比百分比 (与duty互斥)\n");
    printf("  -t, --test=TYPE       测试类型:\n");
    printf("                        basic   - 基础功能测试\n");
    printf("                        sweep   - 频率扫描测试\n");
    printf("                        breath  - 呼吸灯效果\n");
    printf("                        servo   - 舵机控制测试\n");
    printf("  -i, --info            显示PWM设备信息\n");
    printf("  -h, --help            显示帮助信息\n");
    printf("\n示例:\n");
    printf("  %s -c 0 -n 0 -f 1000 -r 50     # 1KHz频率，50%%占空比\n", program_name);
    printf("  %s -t breath -c 0 -n 0         # 呼吸灯效果测试\n", program_name);
    printf("  %s -i                          # 显示系统PWM信息\n", program_name);
}

int run_basic_test(int chip, int channel, unsigned long period, unsigned long duty_cycle) {
    printf("=== PWM基础功能测试 ===\n");
    printf("芯片: %d, 通道: %d\n", chip, channel);
    printf("周期: %lu ns (%.2f Hz)\n", period, 1000000000.0 / period);
    printf("占空比: %lu ns (%.2f%%)\n", duty_cycle, (double)duty_cycle / period * 100);
    
    // 导出PWM
    if (pwm_export(chip, channel) != 0) {
        printf("PWM导出失败\n");
        return -1;
    }
    
    // 设置周期和占空比
    if (pwm_set_period(chip, channel, period) != 0 ||
        pwm_set_duty_cycle(chip, channel, duty_cycle) != 0) {
        printf("PWM参数设置失败\n");
        pwm_unexport(chip, channel);
        return -1;
    }
    
    // 启用PWM
    if (pwm_enable(chip, channel) != 0) {
        printf("PWM启用失败\n");
        pwm_unexport(chip, channel);
        return -1;
    }
    
    printf("PWM已启动，按Ctrl+C退出...\n");
    
    // 等待用户中断
    while (running) {
        usleep(100000); // 100ms
    }
    
    // 关闭PWM
    pwm_disable(chip, channel);
    pwm_unexport(chip, channel);
    printf("PWM测试完成\n");
    
    return 0;
}

int run_sweep_test(int chip, int channel) {
    printf("=== PWM频率扫描测试 ===\n");
    printf("芯片: %d, 通道: %d\n", chip, channel);
    
    if (pwm_export(chip, channel) != 0) {
        printf("PWM导出失败\n");
        return -1;
    }
    
    // 50%占空比
    unsigned long duty_ratio = 50;
    
    printf("开始频率扫描 (100Hz - 10KHz)，按Ctrl+C退出...\n");
    
    if (pwm_enable(chip, channel) != 0) {
        printf("PWM启用失败\n");
        pwm_unexport(chip, channel);
        return -1;
    }
    
    // 频率扫描
    for (int freq = 100; freq <= 10000 && running; freq += 100) {
        unsigned long period = 1000000000UL / freq;
        unsigned long duty = period * duty_ratio / 100;
        
        if (pwm_set_period(chip, channel, period) != 0 ||
            pwm_set_duty_cycle(chip, channel, duty) != 0) {
            continue;
        }
        
        printf("频率: %d Hz, 周期: %lu ns\n", freq, period);
        usleep(500000); // 停留500ms
    }
    
    pwm_disable(chip, channel);
    pwm_unexport(chip, channel);
    printf("频率扫描测试完成\n");
    
    return 0;
}

int run_breathing_test(int chip, int channel) {
    printf("=== PWM呼吸灯效果测试 ===\n");
    printf("芯片: %d, 通道: %d\n", chip, channel);
    
    if (pwm_export(chip, channel) != 0) {
        printf("PWM导出失败\n");
        return -1;
    }
    
    // 1KHz频率
    unsigned long period = 1000000; // 1ms = 1000000ns
    if (pwm_set_period(chip, channel, period) != 0) {
        printf("设置PWM周期失败\n");
        pwm_unexport(chip, channel);
        return -1;
    }
    
    if (pwm_enable(chip, channel) != 0) {
        printf("PWM启用失败\n");
        pwm_unexport(chip, channel);
        return -1;
    }
    
    printf("开始呼吸灯效果，按Ctrl+C退出...\n");
    
    while (running) {
        // 渐亮
        for (int duty = 1; duty <= 99 && running; duty += 2) {
            unsigned long duty_cycle = period * duty / 100;
            pwm_set_duty_cycle(chip, channel, duty_cycle);
            printf("\r亮度: %d%%", duty);
            fflush(stdout);
            usleep(50000); // 50ms
        }
        
        // 渐暗
        for (int duty = 99; duty >= 1 && running; duty -= 2) {
            unsigned long duty_cycle = period * duty / 100;
            pwm_set_duty_cycle(chip, channel, duty_cycle);
            printf("\r亮度: %d%%", duty);
            fflush(stdout);
            usleep(50000); // 50ms
        }
    }
    
    printf("\n");
    pwm_disable(chip, channel);
    pwm_unexport(chip, channel);
    printf("呼吸灯测试完成\n");
    
    return 0;
}

int run_servo_test(int chip, int channel) {
    printf("=== PWM舵机控制测试 ===\n");
    printf("芯片: %d, 通道: %d\n", chip, channel);
    
    if (pwm_export(chip, channel) != 0) {
        printf("PWM导出失败\n");
        return -1;
    }
    
    // 舵机标准频率50Hz (20ms周期)
    unsigned long period = 20000000; // 20ms = 20000000ns
    if (pwm_set_period(chip, channel, period) != 0) {
        printf("设置PWM周期失败\n");
        pwm_unexport(chip, channel);
        return -1;
    }
    
    if (pwm_enable(chip, channel) != 0) {
        printf("PWM启用失败\n");
        pwm_unexport(chip, channel);
        return -1;
    }
    
    printf("舵机控制测试 (0° - 180° - 0°)，按Ctrl+C退出...\n");
    
    while (running) {
        // 0度位置 (1ms脉宽)
        unsigned long duty_0 = 1000000; // 1ms
        pwm_set_duty_cycle(chip, channel, duty_0);
        printf("舵机位置: 0°\n");
        sleep(2);
        if (!running) break;
        
        // 90度位置 (1.5ms脉宽)
        unsigned long duty_90 = 1500000; // 1.5ms
        pwm_set_duty_cycle(chip, channel, duty_90);
        printf("舵机位置: 90°\n");
        sleep(2);
        if (!running) break;
        
        // 180度位置 (2ms脉宽)
        unsigned long duty_180 = 2000000; // 2ms
        pwm_set_duty_cycle(chip, channel, duty_180);
        printf("舵机位置: 180°\n");
        sleep(2);
        if (!running) break;
        
        // 回到90度
        pwm_set_duty_cycle(chip, channel, duty_90);
        printf("舵机位置: 90°\n");
        sleep(2);
    }
    
    pwm_disable(chip, channel);
    pwm_unexport(chip, channel);
    printf("舵机控制测试完成\n");
    
    return 0;
}

int main(int argc, char *argv[]) {
    int chip = 0;
    int channel = 0;
    unsigned long period = 1000000; // 1ms默认周期
    unsigned long duty_cycle = 500000; // 50%占空比
    char test_type[32] = "basic";
    int show_info = 0;
    
    // 长选项定义
    static struct option long_options[] = {
        {"chip",    required_argument, 0, 'c'},
        {"channel", required_argument, 0, 'n'},
        {"period",  required_argument, 0, 'p'},
        {"duty",    required_argument, 0, 'd'},
        {"freq",    required_argument, 0, 'f'},
        {"ratio",   required_argument, 0, 'r'},
        {"test",    required_argument, 0, 't'},
        {"info",    no_argument,       0, 'i'},
        {"help",    no_argument,       0, 'h'},
        {0, 0, 0, 0}
    };
    
    // 解析命令行参数
    int opt;
    int option_index = 0;
    while ((opt = getopt_long(argc, argv, "c:n:p:d:f:r:t:ih", long_options, &option_index)) != -1) {
        switch (opt) {
            case 'c':
                chip = atoi(optarg);
                break;
            case 'n':
                channel = atoi(optarg);
                break;
            case 'p':
                period = strtoul(optarg, NULL, 10);
                break;
            case 'd':
                duty_cycle = strtoul(optarg, NULL, 10);
                break;
            case 'f': {
                int freq = atoi(optarg);
                if (freq > 0) {
                    period = 1000000000UL / freq;
                    duty_cycle = period / 2; // 50%占空比
                }
                break;
            }
            case 'r': {
                int ratio = atoi(optarg);
                if (ratio >= 0 && ratio <= 100) {
                    duty_cycle = period * ratio / 100;
                }
                break;
            }
            case 't':
                strncpy(test_type, optarg, sizeof(test_type) - 1);
                test_type[sizeof(test_type) - 1] = '\0';
                break;
            case 'i':
                show_info = 1;
                break;
            case 'h':
                print_usage(argv[0]);
                return 0;
            default:
                print_usage(argv[0]);
                return 1;
        }
    }
    
    // 注册信号处理器
    signal(SIGINT, signal_handler);
    signal(SIGTERM, signal_handler);
    
    printf("PWM测试程序启动\n");
    printf("========================\n");
    
    // 显示系统信息
    if (show_info) {
        pwm_show_system_info();
        return 0;
    }
    
    // 参数有效性检查
    if (duty_cycle > period) {
        printf("错误：占空比时间不能大于周期时间\n");
        return 1;
    }
    
    // 执行对应的测试
    int result = 0;
    if (strcmp(test_type, "basic") == 0) {
        result = run_basic_test(chip, channel, period, duty_cycle);
    } else if (strcmp(test_type, "sweep") == 0) {
        result = run_sweep_test(chip, channel);
    } else if (strcmp(test_type, "breath") == 0) {
        result = run_breathing_test(chip, channel);
    } else if (strcmp(test_type, "servo") == 0) {
        result = run_servo_test(chip, channel);
    } else {
        printf("错误：未知的测试类型 '%s'\n", test_type);
        printf("支持的测试类型: basic, sweep, breath, servo\n");
        return 1;
    }
    
    return result;
}